臆想的
let fs = require('fs')
function readFile(filename){
...
}
let content = readFile('config.js')
// 针对读取到的内容进行操作,比如打印文件内容
console.log(content)
臆想中,读取文件是有返回值的,将返回值,即文件内容,赋给一个变量,然后决定对读取到的内容进行相应的操作,例如打印文件中的内容。
简而言之,臆想中,读取文件,打印文件是相互分开的。
回调
let fs = require('fs')
function readFile(filename, callback){
fs.readFile(filename, 'utf8', (err, data) => {
if(err){
throw new err
}
callback(data)
})
}
readFile('config.js', data => {
console.log(data)
})
实际上,在经常使用的回调中,读取文件和针对文件内容相应的操作是在一起的,
你在要求读取文件的同时,还要说明获取文件内容后干嘛
这和习惯性思维,你先把文件内容给我,至于我怎么处理,稍后再说
Promise
let fs = require('fs')
function readFile(filename) {
return new Promise(function (resolve) { // 这里的callback,是在run函数中传递的
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
reject(err)
}
resolve(data)
})
})
}
let content = readFile('config.js')
content.then(res => {
console.log(res)
})
// 对比臆想中的
let content = readFile('config.js')
// 针对读取到的内容进行操作,比如打印文件内容
console.log(content)
使用Promise后,整个书写逻辑开始和臆想中的很接近了,读取文件和对文件内容的操作分开了
即通过使用Promise,可以将异步的操作和对异步结果的处理,分开
来实现一个简陋的假的Promise
let fs = require('fs')
function resolve(value) {
let _self = this
setTimeout(function () {
_self.callbacks.forEach(function (callback) {
callback(value);
})
}, 0)
// 保证在resolve执行之前,then方法都已经注册
}
class FakePromise {
constructor(fn) {
// fn是个函数,里面包含异步,异步成功
// Promise在new的过程中就已经开始执行异步代码
// 异步代码执行完触发resolve,resolve作为异步代码的参数,它早已经实现好
this.value = null
this.callbacks = []
fn(resolve.bind(this))
}
then(onFulfilled) {
this.callbacks.push(onFulfilled)
return this
}
}
function readFile(filename) {
return new FakePromise(function (resolve) {
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
return
}
resolve(data)
})
})
}
let content = readFile('config.js')
content.then(res => {
console.log(res)
})
这样看来,Promise和发布-订阅模式有些相像。promise内部也有个事件队列,通过then注册事件,通过resolve触发。每个promise在创建的时候,就开始执行传递给它的函数,函数中会触发resolve,这个resolve就是去执行所有注册的事件。
当然,实际上promise比这强大的多,首先resolve执行所有注册的事件会保证滞后执行,避免还没通过then注册完事件,resolve就执行了
其次,在异步操作成功之后,通过then注册事件,可以立马执行,这就需要给promise添加状态机制
...
then(onFulfilled) {
if (this.state === 'pending') {
this.callbacks.push(onFulfilled)
return this
}
onFulfilled(value)
return this
}
...
判断不是'pending',就立刻执行注册的函数
另外就是每个then()方法,都会返回一个新的promise
大概长这样
then(onFulfilled) {
return new Promise(...)
}
参考资料
生成器
let fs = require('fs')
function run(taskDef){
// 传入的taskDef是个生成器函数,执行后返回迭代器
let task = taskDef()
// 调用迭代器的next()方法,开始taskDef函数中的代码,直至遇到yield,并将yield的值赋予result
let result = task.next()
function step(){
if(!result.done){
if(typeof result.value === 'function'){
result.value((err, data)=>{
if(err){
result = task.throw(err)
return
}
result = task.next(data)
step()
})
// 这里的result.value(...){...}
// 调用的是function(callback){fs.readFile(filename, 'utf8', callback)}
}else{
result = task.next(data)
step() // 判断任务是否执行完
}
}
}
step()
// task.next(data) 继续执行生成器中的代码,并将值传回给触发这次next()的yield的等号左边的变量
}
function readFile(filename){
return function (callback){ // 这里的callback,是在run函数中传递的
fs.readFile(filename, 'utf8', callback)
}
}
run(function*(){
let content = yield readFile('config.js') // 传递函数至run函数中,并由run传递参数调用
// 对文件内容进行处理
console.log(content)
})
// 对比臆想中的
let content = readFile('config.js')
// 针对读取到的内容进行操作,比如打印文件内容
console.log(content)
生成器函数可以停止函数执行,代码在yield readFile('copy.js')
处暂停
异步任务的回调中调用迭代器的next()方法,使生成器函数中的代码继续执行,并通过next()方法传递参数回至生成器函数中,异步任务完成,返回值已经赋值给了content
Promise+generator
let fs = require('fs')
function run(taskDef){
// 传入的taskDef是个生成器函数,执行后返回迭代器
let task = taskDef()
// 调用迭代器的next()方法,开始taskDef函数中的代码,直至遇到yield,并将yield的值赋予result
let result = task.next()
function step(){
if(!result.done){
let promise = Promise.resolve(result.value)
promise.then(value => {
result = task.next(value)
step()
}).catch(err => {
result = task.throw(err)
step()
})
}
}
step()
// task.next(data) 继续执行生成器中的代码,并将值传回给触发这次next()的yield的等号左边的变量
}
function readFile(filename){
return new Promise(function (resolve, reject){ // 这里的callback,是在run函数中传递的
fs.readFile(filename, 'utf8', (err, data) => {
if(err){
reject(err)
}
resolve(data)
})
})
}
run(function*(){
let content = yield readFile('config.js') // 传递函数至run函数中,并由run传递参数调用
// 对文件内容进行处理
console.log(content)
})
console.log('先执行')
Async&await
是不是和promise+generator很像
let fs = require('fs')
function readFile(filename) {
return new Promise(function (resolve) { // 这里的callback,是在run函数中传递的
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
reject(err)
}
resolve(data)
})
})
}
(async function test() {
let content = await readFile('copy.js')
console.log(content)
})()
参考资料
- 深入理解ES6
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。